import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;

/**
 * Created by IntelliJ IDEA.
 * User: Administrator
 * Date: Dec 24, 2009
 * Time: 9:45:24 AM
 * To change this template use File | Settings | File Templates.
 */
public class Scanner {
    /*input file*/
    private static final String INPUT_FILE_NAME = "input.in";
    /*output file*/
    private static final String OUTPUT_FILE_NAME = "tokernizer.out";

    /*tokens*/
    public static final String SCHEMA = "SCHEMA: ";
    public static final String RULE = "RULE: ";
    public static final String DECLARATION = "DECLARATION: ";
    public static final String ATTRIBUTEDECL = "ATTRIBUTEDECL: ";
    public static final String BOOLEXP = "BOOLEXP: ";
    public static final String REGEXP = "REGEXP: ";
    public static final String DEFINITION = "DEFINITION: ";
    public static final String NORMALIZE = "NORMALIZE: ";
    public static final String UNIQUE = "UNIQUE: ";
    public static final String POINTER = "POINTER: ";
    public static final String FIELD = "FIELD: ";
    public static final String IMPORT = "IMPORT: ";
    public static final String PREFIX = "PREFIX: ";
    public static final String COMMENT = "COMMENT: ";
    public static final String DOCCUMENT = "DOCCUMENT: ";
    public static final String PROCESSING_INSTRUCTION = "PROCESSING_INSTRUCTION: ";
    public static final String ATTRIBUTEDEFAULT_OR_CONTENTSDEFAULT = "ATTRIBUTEDEFAULT_OR_CONTENTSDEFAULT: ";
    public static final String ATTRIBUTES = "ATTRIBUTES: ";

    /*ERROR*/
    public static final String ERROR = "ERROR: ";
    public static final String THIS_IS_NOT_A_VALID_DSD20_ELEMENT = "THIS IS NOT A VALID DSD 2.0 ELEMENT";
    /*indent*/
    static String INDENT = "";

    static FileWriter fos;
    static int currentLevel;

    public static void main(String[] args) {
        Reader filer;
        try {
            filer = new FileReader(INPUT_FILE_NAME);
            fos = new FileWriter(OUTPUT_FILE_NAME, true);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = null;
        InputSource is = new InputSource(filer);
        Document document;
        try {
            db = dbf.newDocumentBuilder();
            document = db.parse(is);
            preorderTravers(document); /*traverse root*/
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            fos.write("\r\n");
            fos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void preorderTravers(Node node) {
        scan(node);
        NodeList list = node.getChildNodes();
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            currentLevel++;
        }
        for (int i = 0; i < list.getLength(); i++) {
            preorderTravers(list.item(i));
        }
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            currentLevel--;
        }
    }

    private static void scan(Node node) {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            ////*SCHEMA*/
            if (("dsd").equals(node.getNodeName())) {
                print(SCHEMA + node.getNodeName() + " " + getAttributes(node));
            }
            ////*RULE or DEFINITION*/
            else if (("declare").equals(node.getNodeName()) | ("require").equals(node.getNodeName()) | ("if").equals(node.getNodeName()) | ("rule").equals(node.getNodeName()) | ("unique").equals(node.getNodeName()) | ("pointer").equals(node.getNodeName())) {
                print(RULE + node.getNodeName() /*+ getAttributes(node)*/);
            }
            ////*DEFINITION or REGEXP or BOOLEXP*/
            else if (("contenttype").equals(node.getNodeName()) | ("stringtype").equals(node.getNodeName()) | ("boolexp").equals(node.getNodeName())) {
                print(DEFINITION + node.getNodeName() /*+ getAttributes(node)*/);
            }
            ////*DECLARATION*/
            else if (("attribute").equals(node.getNodeName()) | ("required").equals(node.getNodeName()) | ("contents").equals(node.getNodeName())) {
                print(DECLARATION + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*REGEXP*/
            else if (("sequence").equals(node.getNodeName()) | ("optional").equals(node.getNodeName()) | ("complement").equals(node.getNodeName()) | ("union").equals(node.getNodeName()) | ("intersection").equals(node.getNodeName()) | ("minus").equals(node.getNodeName()) | ("repeat").equals(node.getNodeName()) | ("string").equals(node.getNodeName()) | ("char").equals(node.getNodeName())) {
                print(REGEXP + node.getNodeName() /*+ getAttributes(node)*/);
            }
            ////*BOOLEXP*/
            else if (("and").equals(node.getNodeName()) | ("or").equals(node.getNodeName()) | ("not").equals(node.getNodeName()) | ("imply").equals(node.getNodeName()) | ("equiv").equals(node.getNodeName()) | ("one").equals(node.getNodeName()) | ("parent").equals(node.getNodeName()) | ("ancestor").equals(node.getNodeName()) | ("child").equals(node.getNodeName()) | ("descendant").equals(node.getNodeName()) | ("this").equals(node.getNodeName()) | ("element").equals(node.getNodeName())) {
                print(BOOLEXP + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*NORMALIZE*/
            else if (("normalize").equals(node.getNodeName())) {
                print(NORMALIZE + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*ATTRIBUTEDEFAULT_OR_CONTENTSDEFAULT*/
            else if (("default").equals(node.getNodeName())) {
                print(ATTRIBUTEDEFAULT_OR_CONTENTSDEFAULT + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*UNIQUE*/
            else if (("unique").equals(node.getNodeName())) {
                print(UNIQUE + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*POINTER*/
            else if (("pointer").equals(node.getNodeName())) {
                print(POINTER + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*FIELD*/
            else if (("attributefield").equals(node.getNodeName())) {
                print(FIELD + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*import*/
            else if (("import").equals(node.getNodeName())) {
                print(IMPORT + node.getNodeName()/* + getAttributes(node)*/);
            }
            /////*prefix*/
            else if (node.getNodeName().contains(":")) {
                print(PREFIX + node.getNodeName() /*+ getAttributes(node)*/);
            }
            /////*ERROR-NOT A DSD*/
            else {
                print(ERROR + ": " + node.getNodeName() + THIS_IS_NOT_A_VALID_DSD20_ELEMENT);
            }
        } /*else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
            print(processingInstruction(node));
        } else if (node.getNodeType() == Node.COMMENT_NODE) {
            print(comment(node));
        } else if (node.getNodeType() == Node.DOCUMENT_NODE) {
            print(document(node));
        }*/
    }

    private static String document(Node node) {
        String tag = DOCCUMENT;
        tag += " <?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
        /*tag += "<?";
        tag += node.getNodeName() + " " + node.getTextContent();
        tag += "/>\n";*/
        return tag;
    }

    private static String comment(Node node) {
        String tag = COMMENT;
        tag += node.getTextContent();
        return tag;
    }

    private static String processingInstruction(Node node) {
        String tag = PROCESSING_INSTRUCTION;
        tag += " <?";
        tag += node.getNodeName() + " " + node.getTextContent();
        tag += "/>";
        return tag;
    }

    private static String getAttributes(Node node) {
        String attributes = "";
        if (node.hasAttributes()) {
            attributes += ATTRIBUTES;
            for (int i = 0; i < node.getAttributes().getLength(); i++) {
                NamedNodeMap attribMap = node.getAttributes();
                attributes += " " + attribMap.item(i) + " ";
            }
        }
        return attributes;
    }

    private static void print(String string) {
        for (int i = 0; i < currentLevel; i++) {
            System.out.print(INDENT);
        }
        System.out.println(string);
        for (int i = 0; i < currentLevel; i++) {
            try {
                fos.write(INDENT);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            fos.write(string);
            fos.write("\r\n");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
